package com.woniuxy.service.impl;

import com.woniuxy.entity.Course;
import com.woniuxy.entity.StudentCourse;
import com.woniuxy.mapper.CourseMapper;
import com.woniuxy.mapper.StudentCourseMapper;
import com.woniuxy.service.StudentService;
import com.woniuxy.util.ResponseData;
import com.woniuxy.util.ResponseEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

/**
 * @author ：CuiYC
 * @description：
 * @date ：Created in 2025/3/14 15:00
 * @modified By：
 */
@Service
public class StudentServiceImpl implements StudentService {
    @Resource
    private CourseMapper courseMapper;
    @Resource
    private StudentCourseMapper studentCourseMapper;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    ReentrantLock reentrantLock1 = new ReentrantLock();
    ReentrantLock reentrantLock2 = new ReentrantLock();
    @Override
    public List<Course> queryAllCourse() {
        List<Object> catchCourseObject = redisTemplate.opsForHash().values("CACHE:COURSE:COURSE");
        /**
         * 1.从数据库查询选课信息
         * 2.缓存到redis中
         */
        if(!catchCourseObject.isEmpty()){
            // 将Object列表转换为Course列表
            List<Course> catchCourse = catchCourseObject.stream()
                    .map(obj -> (Course) obj)
                    .collect(Collectors.toList());
            return catchCourse;
        }else {
            //缓存中没有选课数据，从数据库直接查
            List<Course> courses = courseMapper.queryAllCourse();
            // 将查询到的选课数据缓存到redis中
//            for (Course item : courses) {
//                redisTemplate.opsForHash().put("CACHE:COURSE:COURSE", item.getId()+"",  item);
//            }
            Map<String, Course> coursesMap = courses.stream().
                    collect(Collectors.toMap(item -> item.getId() + "", item -> item));
            redisTemplate.opsForHash().putAll("CACHE:COURSE:COURSE", coursesMap);
            return courses;
        }
    }

    @Override
    public ResponseData<?> selectCourse(StudentCourse studentCourse) {
        /**
         * 学生选课
         *      1. 判断学生是否已经选过该课程
         *      2. 判断课程是否已满
         *      3. 判断学生是否已经选过其他课程
         *      4. 插入选课信息到Redis
         *      5. 更新课程信息，主要是选课人数
         */
        List<Object> cacheStudentCourse = redisTemplate.opsForHash().values("CACHE:COURSE:STUDENTCOURSE");
        if(cacheStudentCourse.isEmpty()){
            //缓存中没有选课数据，从数据库直接查
            List<StudentCourse> studentCourses = studentCourseMapper.queryAll();
            if(!studentCourses.isEmpty()){
                for (StudentCourse item : studentCourses) {
                    // 将查询到的选课数据缓存到redis中
                    redisTemplate.opsForHash().put("CACHE:COURSE:STUDENTCOURSE"+item.getStudentId(), item.getCourseId()+"",  item);
                }
//                Map<String, StudentCourse> collect = studentCourses.stream()
//                        .collect(Collectors.
//                                toMap(item -> item.getStudentId() + "", item -> item));
//                redisTemplate.opsForHash()
//                        .putAll("CACHE:COURSE:STUDENTCOURSE"+studentCourse.getStudentId(), collect);
            }
        }
        // 缓存中有选课数据，判断是否已经选过该课程
        Object o = redisTemplate.opsForHash().get("CACHE:COURSE:STUDENTCOURSE" + studentCourse.getStudentId(), studentCourse.getCourseId() + "");
        if(o != null){
            //已经选过该课程
            return ResponseData.fail(ResponseEnum.STUDENT_HAD);
        }
        //这里可以校验学生最大选课数量（不讨论）
        try {
            boolean b = reentrantLock1.tryLock();
            if (b) {
                //学生没选过该课程，判断课程是否已满
                Course cacheCourse = (Course)redisTemplate.opsForHash().get("CACHE:COURSE:COURSE", studentCourse.getCourseId() + "");
                if(cacheCourse.getSelectedStudents() >= cacheCourse.getMaxStudents()){
                    return ResponseData.fail(ResponseEnum.COURSE_FULL);
                }
                //插入选课信息到Redis
                redisTemplate.opsForHash().put("CACHE:COURSE:STUDENTCOURSE"+studentCourse.getStudentId(), studentCourse.getCourseId()+"",  studentCourse);
                //更新课程信息，主要是选课人数
                cacheCourse.setSelectedStudents(cacheCourse.getSelectedStudents()+1);
                redisTemplate.opsForHash().put("CACHE:COURSE:COURSE", studentCourse.getCourseId()+"",  cacheCourse);
                return ResponseData.ok();
            }else {
                return ResponseData.fail(ResponseEnum.SYS_BUSY);
            }
        } finally {
            if (reentrantLock1.isHeldByCurrentThread() && reentrantLock1.isLocked() ) {
                reentrantLock1.unlock(); //当前线程只能释放当前线程锁
            }
        }
    }

    @Override
    public ResponseData<?> selectStudentCourse(Integer studentId) {
        /**
         * 查询学生选课信息
         */
        List<Object> cacheStudentCourse = redisTemplate.opsForHash().values("CACHE:COURSE:STUDENTCOURSE");
        if(cacheStudentCourse.isEmpty()){
            //缓存中没有选课数据，从数据库直接查
            List<StudentCourse> studentCourses = studentCourseMapper.queryAll();
            if(!studentCourses.isEmpty()){
                for (StudentCourse item : studentCourses) {
                    // 将查询到的选课数据缓存到redis中
                    redisTemplate.opsForHash().put("CACHE:COURSE:STUDENTCOURSE"+item.getStudentId(), item.getCourseId()+"",  item);
                }
            }
            //数据库也没缓存信息
        }
        //从缓存中查询学生选课信息
        cacheStudentCourse = redisTemplate.opsForHash().values("CACHE:COURSE:STUDENTCOURSE" + studentId);
        if(cacheStudentCourse.isEmpty()){
            return ResponseData.ok();
        }
        //确实有选课记录，根据选课ID查询课程信息
        List<Course> courses = new ArrayList<>();
        for (Object o : cacheStudentCourse) {
            Course cacheCourse = (Course)redisTemplate.opsForHash().get("CACHE:COURSE:COURSE", ((StudentCourse) o).getCourseId() + "");
            courses.add(cacheCourse);
        }

        return ResponseData.ok(courses);
    }

    @Override
    public ResponseData<?> removeCourse(StudentCourse studentCourse) {
        /**
         * 移除学生选课
         */
        //缓存中必有学生选课记录
        //移除选课记录
        redisTemplate.opsForHash().delete("CACHE:COURSE:STUDENTCOURSE"+studentCourse.getStudentId(), studentCourse.getCourseId()+"");

        List<Object> catchCourseObject = redisTemplate.opsForHash().values("CACHE:COURSE:COURSE");
        if(catchCourseObject.isEmpty()){
            //缓存中没有选课数据，从数据库直接查
            List<Course> courses = courseMapper.queryAllCourse();
            // 将查询到的选课数据缓存到redis中
            for (Course item : courses) {
                redisTemplate.opsForHash().put("CACHE:COURSE:COURSE", item.getId()+"",  item);
            }
        }
        //缓存中有选课数据，更新课程信息，主要是选课人数
        reentrantLock2.lock();
        try {
            //更新课程信息，主要是选课人数
            Course cacheCourse = (Course)redisTemplate.opsForHash().get("CACHE:COURSE:COURSE", studentCourse.getCourseId() + "");
            cacheCourse.setSelectedStudents(cacheCourse.getSelectedStudents()-1);
            redisTemplate.opsForHash().put("CACHE:COURSE:COURSE", studentCourse.getCourseId()+"",  cacheCourse);
        } finally {
            reentrantLock2.unlock();
        }

        //返回结果
        return ResponseData.ok();
    }
}
